﻿
using UnityEngine;
using Newtonsoft.Json;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System;
using B83.Win32;
using System.Collections.Generic;

public class ConfigInfo
{
    public float startTime;
    public float endTime;
    public string path;
}

public class MediaEditInfo
{
    public float startTime;
    public float endTime;
    public string path;
    public int startFrame;
    public int endFrame;
    public int totalFrame;
    public float totalTime;
    public float currentTime;
    public int currentFrame;
    public float currentProgress;
    public float hz = 60;

    public override string ToString()
    {
        StringBuilder builder = new StringBuilder();
        builder.AppendLine(string.Format("起始时间：{0}s", startTime * 0.001f));
        builder.AppendLine(string.Format("当前时间：{0}s", currentTime * 0.001f));
        builder.AppendLine(string.Format("当前进度：%{0}", currentProgress * 100));
        builder.AppendLine(string.Format("结束时间：{0}s", endTime * 0.001f));
        builder.AppendLine(string.Format("视频总时长：{0}s", totalTime * 0.001f));
        return builder.ToString();
    }

}

public class AppConfig
{
    public bool isMute = true;
    public float Volume = 1;
    public float fastfaward_frames_perOpt = 4, in_single_frames_perOpt = 1, jump_forward_frame_perOpt = 0.05f;
    public int screen_resolution_dropdownindex = 0;
    public bool isZhuanma = true;
}

public enum playpauseLastState { Stop, Pause, Playing }

public class AppManager : MonoSingleton<AppManager>
{

    [DllImport("User32.dll", SetLastError = true, ThrowOnUnmappableChar = true, CharSet = CharSet.Auto)]
    public static extern int MessageBox(IntPtr handle, String message, String title, int type);

    const string key_lastOpenDir = "key_lastOpenDir";
    const string key_lastSaveDir = "key_lastSaveDir";
    const string key_appconfig = "key_appconfig";
    public MediaEditInfo currentEditInfo;
    public AppConfig appconfig;
    bool isArrowkeyPresslayed;
    float pressLayedTimer;
    public playpauseLastState lastPlayState;

    protected override void Init()
    {
        base.Init();
        AppConfigLoad();
        UnityDragAndDropHook.InstallHook();
        UnityDragAndDropHook.OnDroppedFiles += OnDragFile;
    }

    protected override void OnDestroy()
    {
        base.OnDestroy();
        UnityDragAndDropHook.OnDroppedFiles -= OnDragFile;
    }

    private void OnDragFile(List<string> aPathNames, POINT aDropPoint)
    {
        if (aPathNames.Count > 0)
        {
            string filepath = aPathNames[0];
            currentEditInfo.path = filepath;
            PlayVideo();
        }
    }

    void Start()
    {
        TimerManager.CreateInstance();
        currentEditInfo = new MediaEditInfo();
    }

    public bool IsPlaying
    {
        get
        {
            return AVProVideoPlayerMgr.Instance.IsPlaying;
        }
    }

    private float TimePerFrame {
        get {
            if (currentEditInfo.hz > 1)
            {
                return 1000f / currentEditInfo.hz;
            }
            return 17.6f;
        }
    }

    private void OnApplicationFocus(bool focus)
    {
        if (focus)
        {
            if (lastPlayState == playpauseLastState.Playing)
            {
                AVProVideoPlayerMgr.Instance.Play();
            }
        }
    }

    void RecordLastPlayState()
    {
        if (AVProVideoPlayerMgr.Instance.IsReady)
        {
            lastPlayState = IsPlaying ? playpauseLastState.Playing : playpauseLastState.Pause;
        }
        else
        {
            lastPlayState = playpauseLastState.Stop;
        }
    }

    void Update()
    {
        TimerManager.Instance.Update();

        if (AVProVideoPlayerMgr.Instance.IsReady)
        {
            currentEditInfo.currentProgress = AVProVideoPlayerMgr.Instance.Progress;
            currentEditInfo.currentTime = currentEditInfo.currentProgress * currentEditInfo.totalTime;

            if (Input.GetKey(KeyCode.LeftArrow) || Input.GetKey(KeyCode.RightArrow))
            {
                if (!isArrowkeyPresslayed)
                {
                    pressLayedTimer += Time.deltaTime;
                    if (pressLayedTimer >= 0.8f)
                    {
                        pressLayedTimer = 0f;
                        isArrowkeyPresslayed = true;
                    }
                }
            }

            if (IsPlaying)
            {
                if (AVProVideoPlayerMgr.Instance.CurrentTimeMs > currentEditInfo.endTime)
                {
                    AVProVideoPlayerMgr.Instance.SeekMs(currentEditInfo.startTime);
                }
            }

            if (Input.GetKeyDown(KeyCode.Space))
            {
                if (IsPlaying)
                {
                    AVProVideoPlayerMgr.Instance.Pause();
                }
                else
                {
                    AVProVideoPlayerMgr.Instance.Play();
                }
            }

            if (Input.GetKeyDown(KeyCode.P))
            {
                UIManager.Instance.ShowHideVideoPlaneOver();
            }

            if (Input.GetKeyDown(KeyCode.A))
            {
                RecordLastPlayState();
                AVProVideoPlayerMgr.Instance.Pause();

                int startFrame = (int)(currentEditInfo.hz * currentEditInfo.startTime * 0.001f);
                int endFrame = (int)(currentEditInfo.hz * currentEditInfo.endTime * 0.001f);
                if (endFrame - startFrame <= 300)
                {
                    string cmdStr = string.Format(@"""VideoPerfectLoop.py"" ""{0}"" {1} {2} ", currentEditInfo.path, startFrame, endFrame);
                    Utils.RunCmd("python.exe", cmdStr);
                    ProcessAutoGenerateData();
                }
                else
                {
                    RecordLastPlayState();
                    AVProVideoPlayerMgr.Instance.Pause();
                    MessageBox(IntPtr.Zero, "要处理的帧数过多，请使用更精确的起始位置！","好的", 0);
                }
            }

            if (Input.GetKeyDown(KeyCode.LeftBracket))
            {
                currentEditInfo.startTime = currentEditInfo.currentTime;
                UIManager.Instance.IdentifyLeft = Progress;
            }

            if (Input.GetKeyDown(KeyCode.RightBracket))
            {
                currentEditInfo.endTime = currentEditInfo.currentTime;
                UIManager.Instance.IdentifyRight = Progress;
            }

            if (Input.GetKeyDown(KeyCode.M))
            {
                appconfig.isMute = !appconfig.isMute;
                AVProVideoPlayerMgr.Instance.IsMute = appconfig.isMute;
                AppConfigSave();
            }

            if (Input.GetKeyDown(KeyCode.KeypadPlus))
            {
                AVProVideoPlayerMgr.Instance.Volume += 0.1f;
                appconfig.Volume = AVProVideoPlayerMgr.Instance.Volume;
                AppConfigSave();
            }

            if (Input.GetKeyDown(KeyCode.KeypadMinus))
            {
                AVProVideoPlayerMgr.Instance.Volume -= 0.1f;
                appconfig.Volume = AVProVideoPlayerMgr.Instance.Volume;
                AppConfigSave();
            }

            if (!IsPlaying)
            {
                if (Input.GetKeyDown(KeyCode.Home))
                {
                    Progress = 0;
                }

                if (Input.GetKeyDown(KeyCode.End))
                {
                    Progress = 1;
                }

                if (Input.GetKeyDown(KeyCode.PageUp))
                {
                    Progress -= appconfig.jump_forward_frame_perOpt;
                }

                if (Input.GetKeyDown(KeyCode.PageDown))
                {
                    Progress += appconfig.jump_forward_frame_perOpt;
                }
                if (Input.GetKeyDown(KeyCode.Insert))
                {
                    Progress = currentEditInfo.startTime / currentEditInfo.totalTime;
                }

                if (Input.GetKeyDown(KeyCode.Delete))
                {
                    Progress = currentEditInfo.endTime / currentEditInfo.totalTime;
                }
                UIManager.Instance.SliderValue = Progress;

                if (Input.GetKeyDown(KeyCode.LeftArrow))
                {
                    Progress = (currentEditInfo.currentTime - TimePerFrame * appconfig.in_single_frames_perOpt) / currentEditInfo.totalTime;
                }
                if (Input.GetKeyDown(KeyCode.RightArrow))
                {
                    Progress = (currentEditInfo.currentTime + TimePerFrame * appconfig.in_single_frames_perOpt) / currentEditInfo.totalTime;
                }

                if (isArrowkeyPresslayed)
                {
                    if (Input.GetKey(KeyCode.LeftArrow))
                    {
                        Progress = (currentEditInfo.currentTime - TimePerFrame * appconfig.fastfaward_frames_perOpt) / currentEditInfo.totalTime;
                    }
                    if (Input.GetKey(KeyCode.RightArrow))
                    {
                        Progress = (currentEditInfo.currentTime + TimePerFrame * appconfig.fastfaward_frames_perOpt) / currentEditInfo.totalTime;
                    }
                    if (Input.GetKeyUp(KeyCode.LeftArrow) || Input.GetKeyUp(KeyCode.RightArrow))
                    {
                        isArrowkeyPresslayed = false;
                    }
                }
            }
        }

        if (Input.GetMouseButtonUp(2))
        {
            RecordLastPlayState();
            AVProVideoPlayerMgr.Instance.Pause();
            OpenVideoFile("mp4");
        }

        if (Input.GetKeyDown(KeyCode.F))
        {
            ProcessAutoGenerateData();
        }

        if (Input.GetKeyDown(KeyCode.S))
        {
            CutCurrentVideo();
        }

    }

    private void CutCurrentVideo()
    {
        string save_name = GetCutVideoSaveDir("mp4");
        if (!string.IsNullOrEmpty(save_name))
        {
            float beginSec = currentEditInfo.startTime * 0.001f;
            float endSec = currentEditInfo.endTime * 0.001f;
            string cmdStr = "";
            if (appconfig.isZhuanma)
            {
                cmdStr = string.Format(@" -y -ss {0} -t {1} -i ""{2}"" -c:v libx264 -c:a aac -strict experimental -b:a 640k ""{3}"""
               , beginSec, endSec - beginSec, currentEditInfo.path, save_name);
            }
            else
            {
                cmdStr = string.Format(@" -y -accurate_seek -ss {0} -t {1} -i ""{2}"" -acodec copy -vcodec copy -async 1 -avoid_negative_ts 1 ""{3}"""
                   , beginSec, endSec - beginSec, currentEditInfo.path, save_name);
            }

            string ffmpeg_exepath = "ffmpeg.exe";
            Utils.RunCmd(ffmpeg_exepath, cmdStr);
        }
    }

    private void ProcessAutoGenerateData()
    {
        string jsonStr = File.ReadAllText("config.json");
        ConfigInfo config = JsonConvert.DeserializeObject<ConfigInfo>(jsonStr);
        currentEditInfo.path = config.path;
        currentEditInfo.startTime = config.startTime;
        currentEditInfo.endTime = config.endTime;
        PlayVideo(false);
    }

    private void OnGUI()
    {
        if (currentEditInfo != null)
        {
            GUI.color = Color.red * 0.7f;
            GUI.Label(new Rect(0, 0, 200, 300), this.currentEditInfo.ToString());
        }
    }

    public float Progress
    {
        get
        {
            return currentEditInfo.currentProgress;
        }
        set
        {
            AVProVideoPlayerMgr.Instance.Progress = value;
        }
    }

    public void PlayVideo(bool isDefault = true)
    {
        bool issucess = AVProVideoPlayerMgr.Instance.PlayVideo(RenderHeads.Media.AVProVideo.MediaPlayer.FileLocation.AbsolutePathOrURL, currentEditInfo.path, true);
        if (issucess)
        {

            AVProVideoPlayerMgr.Instance.ready_callback = () =>
            {

                currentEditInfo.totalTime = AVProVideoPlayerMgr.Instance.Mediaplayer.Info.GetDurationMs();
                if (isDefault) currentEditInfo.endTime = currentEditInfo.totalTime;
                UIManager.Instance.IdentifyLeft = currentEditInfo.startTime / currentEditInfo.totalTime;
                UIManager.Instance.IdentifyRight = currentEditInfo.endTime / currentEditInfo.totalTime;

                TimerManager.Instance.AddTimer(.5f, () => {
                    Texture mainTexture = AVProVideoPlayerMgr.Instance.mainTexture;
                    UIManager.Instance.VideoPlaneTexture = mainTexture;
                    AVProVideoPlayerMgr.Instance.SeekMs(currentEditInfo.startTime);
                    AVProVideoPlayerMgr.Instance.Volume = appconfig.Volume;
                    AVProVideoPlayerMgr.Instance.IsMute = appconfig.isMute;
                    UIManager.Instance.SetVideoPanelScaleFromTex(mainTexture);

                    TimerManager.Instance.AddTimer(1f, () => {
                        currentEditInfo.hz = AVProVideoPlayerMgr.Instance.CurrentFrameRate;
                        Debug.Log(currentEditInfo.hz);
                    });

                });
            };
        }
    }

    public void OpenVideoFile(string type)
    {
        string lastDir = PlayerPrefs.HasKey(key_lastOpenDir) ? PlayerPrefs.GetString(key_lastOpenDir) : "D:/";

        OpenFileName openFileName = new OpenFileName();
        openFileName.structSize = Marshal.SizeOf(openFileName);
        openFileName.filter = "*.mp4,*.avi,*.wmv";
        openFileName.file = new string(new char[256]);
        openFileName.maxFile = openFileName.file.Length;
        openFileName.fileTitle = new string(new char[64]);
        openFileName.maxFileTitle = openFileName.fileTitle.Length;
        openFileName.initialDir = lastDir;
        openFileName.title = "选择视频";
        openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;

        if (LocalDialog.GetOFN(openFileName))
        {
            //TODO
            Debug.Log(openFileName.file);
            PlayerPrefs.SetString(key_lastOpenDir, Path.GetDirectoryName(openFileName.file));
            currentEditInfo.path = openFileName.file;
            PlayVideo();

        }
    }

    public string GetCutVideoSaveDir(string type)
    {
        string lastDir = PlayerPrefs.HasKey(key_lastSaveDir) ? PlayerPrefs.GetString(key_lastSaveDir) : "D:/";

        OpenFileName openFileName = new OpenFileName();
        openFileName.structSize = Marshal.SizeOf(openFileName);
        openFileName.filter = "*.*";
        openFileName.file = new string(new char[256]);
        openFileName.maxFile = openFileName.file.Length;
        openFileName.fileTitle = new string(new char[64]);
        openFileName.maxFileTitle = openFileName.fileTitle.Length;
        openFileName.initialDir = lastDir;
        openFileName.title = "保存路径";
        openFileName.flags = 0x00080000 | 0x00001000 | 0x00000800 | 0x00000008;

        if (LocalDialog.GetSFN(openFileName))
        {
            //TODO
            Debug.Log(openFileName.file);
            PlayerPrefs.SetString(key_lastSaveDir, Path.GetDirectoryName(openFileName.file));

            return openFileName.file;
        }
        return null;
    }

    public void AppConfigLoad()
    {
        if (PlayerPrefs.HasKey(key_appconfig))
        {
            string json_str = PlayerPrefs.GetString(key_appconfig);
            this.appconfig = JsonConvert.DeserializeObject<AppConfig>(json_str);
        }
        else
        {
            this.appconfig = new AppConfig();
        }
    }

    public void AppConfigSave()
    {
        string json_str = JsonConvert.SerializeObject(this.appconfig);
        PlayerPrefs.SetString(key_appconfig, json_str);
    }

}
